package com.xiejun.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioSelectorServer {

    public static void main(String[] args) {
        try {
            // 打开一个选择器
            Selector selector = Selector.open();

            // 打开一个服务器套接字通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式

            // 将服务器套接字通道绑定到指定的端口
            serverSocketChannel.socket().bind(new InetSocketAddress(9000));

            // 将服务器套接字通道注册到选择器上，监听接受事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("NIO Selector Server is starting...");

            while (true) {
                // 阻塞等待事件发生
                selector.select();

                // 获取就绪的键集合
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isAcceptable()) {
                        // 处理接受事件
                        handleAccept(key, selector);
                    } else if (key.isReadable()) {
                        // 处理读事件
                        handleRead(key);
                    }

                    // 移除已经处理过的键
                    keyIterator.remove();
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handleAccept(SelectionKey key, Selector selector) throws IOException {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
        SocketChannel clientSocketChannel = serverSocketChannel.accept();
        clientSocketChannel.configureBlocking(false); // 设置为非阻塞模式

        // 将客户端套接字通道注册到选择器上，监听读事件
        clientSocketChannel.register(selector, SelectionKey.OP_READ);

        System.out.println("Accepted new connection from " + clientSocketChannel.getRemoteAddress());
    }

    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel clientSocketChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        int bytesRead = clientSocketChannel.read(buffer);

        if (bytesRead == -1) {
            // 客户端关闭连接
            clientSocketChannel.close();
            System.out.println("Closed connection from " + clientSocketChannel.getRemoteAddress());
        } else {
            // 处理读取的数据
            String receivedData = new String(buffer.array(), 0, bytesRead);
            System.out.println("Received data from " + clientSocketChannel.getRemoteAddress() + ": " + receivedData);

            // 回复客户端
            ByteBuffer responseBuffer = ByteBuffer.wrap(("Echo: " + receivedData).getBytes());
            clientSocketChannel.write(responseBuffer);
        }
    }
}
